package com.yanqu.road.connect;

import com.yanqu.road.NettyMgr;
import com.yanqu.road.handle.AgentServerHandler;
import com.yanqu.road.initialize.YanQuCHInitializer;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.ServerType;
import com.yanqu.road.utils.net.ServerNetConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AgentServerConnectionGroup extends ServerConnectionGroup {

    private static Logger logger = LogManager.getLogger(AgentServerConnectionGroup.class.getName());

    protected YanQuMessage firstMsg;
    protected InetSocketAddress addr;
    private Map<Integer, AgentServerEventLoopGroup> eventLoopGroupMap;

    public AgentServerConnectionGroup(InetSocketAddress addr, YanQuMessage firstMsg, int size, ServerNetConfig serverNetConfig, int serverType) {
        super(serverNetConfig.getAddress(), serverNetConfig.getName(), size, serverNetConfig.getServerIndex(), serverNetConfig.getPort(), serverType);
        this.addr = addr;
        this.firstMsg = firstMsg;
        eventLoopGroupMap = new ConcurrentHashMap<>();
    }

    public ChannelHandler createChannelHandler() {
        return new AgentServerHandler();
    }

    @Override
    public YanQuConnection connect(int i) throws Exception {
        if (!eventLoopGroupMap.containsKey(i)) {
            eventLoopGroupMap.put(i, new AgentServerEventLoopGroup());
        }
        AgentServerEventLoopGroup serverEventLoopGroup = eventLoopGroupMap.get(i);
        closeOldConnection(serverEventLoopGroup);
        return executeConn(i, serverEventLoopGroup);
    }

    /**
     * 执行连接
     *
     * @param i
     * @param serverEventLoopGroup
     * @return
     */
    private YanQuConnection executeConn(int i, AgentServerEventLoopGroup serverEventLoopGroup) {
        serverEventLoopGroup.setGroup(new NioEventLoopGroup(Runtime.getRuntime().availableProcessors()));
        EventLoopGroup workerGroup = serverEventLoopGroup.getGroup();
        Bootstrap bootstrap = getBootstrap(workerGroup);

        try {
            ChannelFuture channelFuture = bootstrap.connect(addr).syncUninterruptibly();
            serverEventLoopGroup.setFuture(channelFuture);
            if (channelFuture.isSuccess() && channelFuture.channel().isActive()) {
                YanQuConnection connection = this.createConnection(channelFuture.channel(), i, addr);
                connection.setConnectionId(i);
                //   connection.write(firstMsg);
                return connection;
            } else {
                logger.error("连接异常, channelFuture状态 : " + channelFuture.isSuccess() + ", active状态 : " + channelFuture.channel().isActive());
            }
        } catch (Exception ex) {
            workerGroup.shutdownGracefully();
            throw ex;
        }
        return null;
    }

    private static void closeOldConnection(AgentServerEventLoopGroup serverEventLoopGroup) {
        try {
            if (serverEventLoopGroup.getGroup() != null && serverEventLoopGroup.getFuture() != null) {
                if (serverEventLoopGroup.getFuture().channel().isActive()) {
                    serverEventLoopGroup.getFuture().channel().close();
                }
                serverEventLoopGroup.getGroup().shutdownGracefully();
            }
        } catch (Exception ex) {
            logger.error("connect error:", ex);
        }
    }

    private Bootstrap getBootstrap(EventLoopGroup workerGroup) {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workerGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
        bootstrap.option(ChannelOption.TCP_NODELAY, true);
        bootstrap.option(ChannelOption.SO_RCVBUF, 1024 * 32);
        bootstrap.option(ChannelOption.SO_SNDBUF, 1024 * 32);
        bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 300);
        bootstrap.handler(new YanQuCHInitializer(createChannelHandler()));
        return bootstrap;
    }

    @Override
    protected YanQuConnection createConnection(Channel channel, int index, InetSocketAddress addr) {
        YanQuConnection connection = new YanQuConnection(channel, true, 1024, index);
        allConnections[index] = connection;
        setEffective(true);
        return connection;
    }

    public void receiveHeartBeat(int index) {
        Connection connection = allConnections[index];
        connection.setLastHeartTime(System.currentTimeMillis());
    }

    @Override
    public void keepAlive() {
        long nowTime = System.currentTimeMillis();
        long loseHeartLimitTime = 2 * 60 * 1000L;
        int size = (allConnections != null) ? allConnections.length : 0;
        for (int connectionIndex = 0; connectionIndex < size; connectionIndex++) {
            synchronized (this) {
                Connection connection = allConnections[connectionIndex];
                if (getServerType() == ServerType.SERVER_CROSS
                        || getServerType() == ServerType.SERVER_CROSS_2
                        || getServerType() == ServerType.CENTER_CROSS_2
                        || getServerType() == ServerType.BANQUET_CROSS
                ) {
                    // 2分钟内没收到回复才往下继续走
                    if (isConnectionAlive(connection) && nowTime < connection.getLastHeartTime() + loseHeartLimitTime) {
                        continue;
                    }

                    if (null != connection) {
                        logger.error("连接检测超时 连接索引:{},当前时间:{}, 检测时间:{}", connectionIndex, nowTime, connection.getLastHeartTime());
                    }
                } else if (isConnectionAlive(connection)) {
                    continue;
                }

                if (tryConnect(connectionIndex)){
                    break;
                }
            }

        }
    }

    private boolean tryConnect(int connectionIndex) {
        try {
            YanQuConnection tmpConn = connect(connectionIndex);
            if (tmpConn == null) {
                return true;
            }
            tmpConn.setLastHeartTime(System.currentTimeMillis());
            allConnections[connectionIndex] = tmpConn;
            onReconnectSuccess(tmpConn);
        } catch (Exception e) {
            logger.error("索引:" + connectionIndex + ",地址:" + addr, e);
            return true;
        }
        return false;
    }

    public void onReconnectSuccess(YanQuConnection connection) {
        int linkIndex = connection.getLinkIndex();
        AgentServerLinkControl.sendRegisterServer(connection, linkIndex, getServerType());
        connection.getChannel().attr(NettyMgr.LINKED_CLIENT).set(this);
    }

    public void send(YanQuMessage packet) {
        write(packet.getPlayerId(), packet);
    }


    public boolean reConnect() {
        keepAlive();
        List<YanQuConnection> connectionList = getAllConnectionList();
        for (YanQuConnection connection : connectionList) {
            if (connection == null || !connection.isAlive()) {
                return false;
            }
        }

        return true;
    }

    @Override
    public String toString() {
        return "serverName : " + serverName + " , serverType : " + serverType + " ,serverId  : " + serverId + " ,  ipAddress : " + ipAddress + " , port : " + port;
    }


}
